package com.jiangxjsy.gateway.filter;

import cn.hutool.core.util.CharsetUtil;
import com.jiangxjsy.core.constant.BasicConstant;
import com.jiangxjsy.core.constant.GatewayConstant;
import com.jiangxjsy.core.exception.BasicException;
import com.jiangxjsy.core.wrap.Result;
import com.jiangxjsy.core.wrap.ResultBuilder;
import com.jiangxjsy.core.wrap.ResultCode;
import com.jiangxjsy.gateway.service.security.PermissionService;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.annotation.Resource;

/**
 * wukong-crm-master
 * 蒋胜宇
 * 2025/5/31 17:37
 *
 * <p>
 * 鉴权过滤器
 * </p>
 *
 * <p>
 * 如果白名单过滤器和忽略拦截过滤器执行完后仍然没有放行请求，
 * 说明该请求需要权限访问，则进行权限校验
 * 鉴于项目使用 jwt 来生成 token，首先需要先验证 token 是否有效，
 * 即先判断 token 是否已验证
 * 如果 token 有效，则判断该 token 是否有权限访问该资源，
 * 此时需要远程访问权限服务，判断该 token 是否有权限访问该资源，
 * 如果网关拒绝，返回 401 - 无权限操作
 * 如果网关允许，则放行请求，此时理论上来说就会触发网关的负载均衡策略
 * - 扩展 -
 * 与前两个过滤器原理类似，
 * router.RouteRepository中已经加载了来自数据库中的路由配置，包括负载均衡
 * 所以一旦放行，则请求会经过负载均衡策略
 * </p>
 */

@Component
public class AuthorizationFilter implements GlobalFilter, Ordered {
    @Resource
    private PermissionService permissionService;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        if (exchange.getAttribute(GatewayConstant.SKIP_SUBSEQUENT_FILTERS) != null) {
            return chain.filter(exchange);
        }

        ServerHttpRequest request = exchange.getRequest();
        String url = request.getPath().value();
        String method = request.getMethodValue();
        String token = request.getHeaders().getFirst(BasicConstant.TOKEN_NAME);

        if (!permissionService.isTokenAuthenticated(token, url, request.getCookies())) {
            throw new BasicException(ResultCode.SystemResultCode.SYSTEM_NOT_LOGIN);
        }

        if (!permissionService.hasPermission(token, url, method)) {
            exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
            Result<?> result = ResultBuilder.error(ResultCode.SystemResultCode.SYSTEM_NO_AUTH);
            DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(
                    result.toJSONString().getBytes(CharsetUtil.systemCharset())
            );
            return exchange.getResponse().writeWith(Flux.just(buffer));
        }

        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        // 鉴权过滤器第 3 执行
        return GatewayConstant.FILTER_HIGHEST_ORDER + 2;
    }
}
